package com.spring.proxy;

import com.spring.annotation.Transactional;

import com.spring.factory.DefaultBeanFactory;
import com.spring.util.Manager;
import com.spring.util.ReflectionUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxyStrategy implements ProxyStrategy {
    @Override
    public <T> T doProxy(T object) {
        return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), object.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                Object returnValue = null;
                boolean doTransaction = false;
                Class<?> clazzRollback = null;
                Method method2 = null;
                if(object.getClass().isAnnotationPresent(Transactional.class) ){
                    clazzRollback = object.getClass().getAnnotation(Transactional.class).rollbackFor();
                    doTransaction = true;
                } else if(method.isAnnotationPresent(Transactional.class)){
                    clazzRollback = method.getAnnotation(Transactional.class).rollbackFor();
                    doTransaction = true;
                } else if((method2 = ReflectionUtils.getMethodOfObject(object,method.getName())) != null){
                    if(method2.isAnnotationPresent(Transactional.class)){
                        clazzRollback = method2.getAnnotation(Transactional.class).rollbackFor();
                        doTransaction = true;
                    }
                }

                Manager transactionManager = null;
                try{

                    if(doTransaction){
                        transactionManager = DefaultBeanFactory.getInstance().getBean("transactionManager");
                        transactionManager.beginTransaction();
                    }

                     returnValue = method.invoke(object, args);

                    if(doTransaction){
                        transactionManager.commit();
                    }
                } catch (Exception e){
                    transactionManager.rollback();
                    throw e;
                }

                return returnValue;
            }
        });
    }
}
